#!/usr/bin/perl
use FindBin;
use lib "$FindBin::Bin/../pllib/lib/perl5";
use lib "$FindBin::Bin/../lib";

use strict;
use POSIX qw(strftime);
use IO::File;
use JSON;
use Getopt::Long;

use AutoExecUtils;

sub usage {
    my $pname = $FindBin::Script;

    print("$pname --backup 0|1 --content <sysctl.conf content>\n");
    exit(1);
}

sub backup {
    my ($filePath)  = @_;
    my $dateTimeStr = strftime( "%Y%m%d-%H%M%S", localtime() );
    my $exitCode    = system(qq{cp "$filePath" "$filePath.$dateTimeStr"});
    return $exitCode;
}

sub getShmAllAndMax {
    my $pageSizeTxt = `getconf PAGESIZE`;
    my $pageSize    = int($pageSizeTxt);

    #MemTotal:        3880620 kB
    #Mem in KB
    my $memTotalTxt = `grep MemTotal /proc/meminfo`;
    my $memTotal    = int($memTotalTxt);
    if ( $memTotalTxt =~ /(\d+)[^\d]+kB/i ) {
        $memTotal = int($1) * 1024;
    }
    elsif ( $memTotalTxt =~ /(\d+)[^\d]+MB/i ) {
        $memTotal = int($1) * 1024 * 1024;
    }
    elsif ( $memTotalTxt =~ /(\d+)[^\d]+GB/i ) {
        $memTotal = int($1) * 1024 * 1024 * 1024;
    }

    my $shmall = $memTotal / 2 / $pageSize;
    my $shmmax = $memTotal / 2 - 1;

    #最小4G
    my $mem4G      = 4294967296;
    my $mem4GPages = 4294967296 / $pageSize;
    if ( $shmmax < $mem4G ) {
        $shmmax = $mem4G - 1;
    }
    if ( $shmall < $mem4GPages ) {
        $shmall = $mem4GPages;
    }

    return ( $shmall, $shmmax );
}

sub main {
    $| = 1;    #不对输出进行buffer，便于实时看到输出日志
    my $filePath = '/etc/sysctl.conf';

    my $needBackup = 0;
    my $autoSetShm = 1;
    my $content;

    GetOptions(
        'backup=i'      => \$needBackup,
        'autotuneshm=i' => \$autoSetShm,
        'content=s'     => \$content
    );

    if ( not defined($content) or $content eq '' ) {
        print("ERROR: Must defined modify content by option --content\n");
        usage();
    }

    my $hasError = 0;

    my $scriptDir = $FindBin::Bin;
    chdir($scriptDir);

    my $confMap       = {};
    my @confKeysArray = ();
    $content =~ s/\\n/\n/sg;
    foreach my $line ( split( /\n/, $content ) ) {
        $line =~ s/^\s*|\s*$//g;
        if ( $line eq '' or $line =~ /^#/ ) {
            next;
        }

        my ( $key, $val ) = split( /\s*=\s*/, $line );
        $confMap->{$key} = $val;
        push( @confKeysArray, $key );
    }

    my ( $shmall, $shmmax );
    if ( $autoSetShm == 1 ) {
        ( $shmall, $shmmax ) = getShmAllAndMax();
        if ( defined( $confMap->{'kernel.shmall'} ) ) {
            $confMap->{'kernel.shmall'} = $shmall;
        }
        if ( defined( $confMap->{'kernel.shmmax'} ) ) {
            $confMap->{'kernel.shmmax'} = $shmmax;
        }
    }

    my $processedMap = {};
    my $isChanged    = 0;
    my $newContent   = '';
    my $fh           = IO::File->new("+<$filePath");
    if ( defined($fh) ) {
        my $line;
        while ( $line = $fh->getline() ) {
            if ( $line !~ /^\s*$/ and $line !~ /^\s*#/ ) {
                my $tmpLine = $line;
                $tmpLine =~ s/^\s*|\s*$//g;
                my ( $key, $val ) = split( /\s*=\s*/, $tmpLine );
                my $newVal = $confMap->{$key};
                if ( defined($newVal) ) {

                    #delete( $confMap->{$key} );
                    $processedMap->{$key} = 1;
                    if ( $newVal ne $val ) {
                        $isChanged = 1;
                        $line =~ s/\s*=.*$/ = $newVal/;
                        print("Replace: $tmpLine -> $line");
                    }
                    else {
                        print("NotChanged: $line");
                    }
                }
            }
            $newContent = $newContent . $line;
        }

        #while ( my ( $key, $val ) = each(%$confMap) ) {
        foreach my $key (@confKeysArray) {
            if ( $processedMap->{$key} == 1 ) {
                next;
            }

            my $val = $confMap->{$key};
            $isChanged  = 1;
            $newContent = $newContent . "$key = $val\n";
            print("Append: $key = $val\n");
        }

        if ( $isChanged == 1 ) {
            if ( $needBackup == 1 ) {
                my $exitCode = backup($filePath);
                if ( $exitCode != 0 ) {
                    print("ERROR: Backup file:$filePath failed, $!\n");
                    $hasError = 2;
                }
            }

            if ( $hasError == 0 ) {
                $fh->seek( 0, 0 );
                $fh->truncate(0);
                $fh->write( $newContent, length($newContent) );
            }
        }

        $fh->close();
        my $out = { sysctlConf => $newContent };
        AutoExecUtils::saveOutput($out);
    }
    else {
        $hasError = 1;
        print("ERROR: Can not open file:$filePath, $!\n");
    }

    return $hasError;
}

exit main();
